package chap_03_ThreadLocal;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

/**
 * @Description 由 ThreadLocalMap 发散的强软弱虚引用学习
 * @Author shihan
 * @Date 2022/11/5 14:53
 * @Version 1.0
 */
public class ThreadLocal_demo_03_reference {

    public static void main(String[] args) {
        //strongReference();
        //softReference();

        weakReference();

    }

    /**
     * 弱引用：
     * 1、用 WeakReference 对象包裹；
     * 2、只要触发 gc，弱引用对象就会被回收；
     */
    private static void weakReference() {
        Object o = new Object();
        WeakReference<MyObject> weakReference = new WeakReference<>(new MyObject());
        System.out.println(o);
        System.out.println("before gc，打印引用对象：" + weakReference.get());
        // 手动建议触发 GC
        System.gc();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(o);
        System.out.println("after gc，打印引用对象：" + weakReference.get());
    }

    /**
     * 软引用：
     * 1、需要用 SoftReference 对象进行包裹；
     * 2、内存够用时不会回收，内存不够用时，会回收软引用对象的内存空间；
     */
    private static void softReference() {
        SoftReference<MyObject> softReference = new SoftReference<>(new MyObject());
        // 手动建议触发 GC
        System.gc();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("内存够用，打印引用对象：" + softReference.get());

        try {
            // 需要配置 JVM 参数：-Xms10m -Xmx10m
            // 开辟一个 10M 的内存对象
            byte[] bytes = new byte[10 * 1024 * 1024];
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 为什么要放在 finally 里，是因为发生的是 OOM Error，Exception 并不能捕获到，所以导致 main 直接结束
            // 而 finally 不管怎么样都会执行
            System.out.println("内存不够用，打印引用对象：" + softReference.get());
        }
    }

    /**
     * 默认创建的对象都是强引用对象
     */
    private static void strongReference() {
        MyObject myObject = new MyObject();
        System.out.println("before gc --> " + myObject);

        // 将强引用对象置为 null，目的是让 GC Root 判定当前对象没有任何引用，可以进行垃圾回收
        myObject = null;
        // 手动触发 gc (并不会立即执行，还是要等线程调度来处理的)
        System.gc();

        try {
            // 等一会儿让 gc 先执行
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 看 gc 后的对象
        System.out.println("after gc --> " + myObject);
    }

}

class MyObject {

    /**
     * GC 垃圾收集器回收对象前，会先调用其 finalize 方法
     *
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        System.out.println("....finalize 方法被执行了....");
    }
}
